package com.mall.b2c.plugin.payment.allinpay;

import java.math.BigDecimal;
import java.util.List;
import java.util.Map;

import net.sf.json.JSONObject;

import org.apache.commons.lang.StringUtils;

import com.allinpay.ets.client.RequestOrder;
import com.mall.b2c.domain.member.MemberDomain;
import com.mall.b2c.domain.order.OrderDomain;
import com.mall.b2c.plugin.payment.AbstractPaymentPlugin;
import com.mall.b2c.plugin.payment.IPaymentEvent;
import com.mall.b2c.util.SerialNumberUtil;
import com.mall.b2c.util.SettingUtils;
import com.mall.common.domain.component.ComponentDomain;
import com.mall.common.domain.component.PaymentLogDomain;
import com.mall.common.exception.NoticeException;
import com.mall.common.util.AppContext;
import com.mall.common.util.DateHelper;

public class AllinpayPlugin extends AbstractPaymentPlugin implements IPaymentEvent {

	@SuppressWarnings("unchecked")
	@Override
	public String onPay(ComponentDomain component, OrderDomain order, String bankInfo, String pickupUrl, String receiveUrl)
			throws Exception {
		JSONObject jsonObject = null;
		if(component.getIsOfficial() != null && component.getIsOfficial() == Boolean.TRUE){
			jsonObject = component.getConfigJson("payConfig");
		}else{
			jsonObject = component.getConfigJson("testConfig");
		}
		if(jsonObject == null){
			throw new NoticeException("系统出错，无法进行支付");
		}
		Map<String, String> params = (Map<String, String>) JSONObject.toBean(jsonObject, Map.class);
		
		if(component.getIsOfficial() != null && component.getIsOfficial() == Boolean.TRUE){
			params.put("issuerId", bankInfo);
		}
		order.setTradeNo(SerialNumberUtil.buildTradeNo());
		BigDecimal totalCost = order.getCash();
		totalCost = totalCost.multiply(new BigDecimal(100)).setScale(0);
		MemberDomain member = order.getMember();
		String orderDatetime = DateHelper.date2String(order.getCreateDate(), "yyyyMMddHHmmss");
		
		//构造订单请求对象，生成signMsg。
		RequestOrder requestOrder = new RequestOrder();
		requestOrder.setInputCharset(Integer.parseInt(params.get("inputCharset")));
		requestOrder.setPickupUrl(pickupUrl);
		requestOrder.setReceiveUrl(receiveUrl);
		requestOrder.setVersion(params.get("version"));
		requestOrder.setSignType(Integer.parseInt(params.get("signType")));
		requestOrder.setPayType(Integer.parseInt(params.get("payType")));
		if(component.getIsOfficial() != null && component.getIsOfficial() == Boolean.TRUE){
			requestOrder.setIssuerId(params.get("issuerId"));
		}
		requestOrder.setMerchantId(params.get("merchantId"));
		requestOrder.setPayerName(member.getUsername());
		requestOrder.setOrderNo(order.getTradeNo());
		requestOrder.setOrderAmount(totalCost.longValue());
		requestOrder.setOrderCurrency(params.get("orderCurrency"));
		requestOrder.setOrderDatetime(orderDatetime);
		if(order.getExpired() != null){
			long orderExpireDatetime = order.getExpired().getTime() - System.currentTimeMillis();
			orderExpireDatetime = orderExpireDatetime/1000/60;
			requestOrder.setOrderExpireDatetime(orderExpireDatetime + "");
		}
		requestOrder.setProductName(SettingUtils.get().getName() + "订单");
		requestOrder.setProductNum(1);
		requestOrder.setKey(params.get("key")); //key为MD5密钥，密钥是在通联支付网关会员服务网站上设置。
		String strSignMsg = requestOrder.doSign(); // 签名，设为signMsg字段值。
		String url = params.get("url");
		return buildRequest(requestOrder.getSrc(), "post", strSignMsg, url);
	}

	@Override
	public String onReturn(Long memberId, Map<String, String> params) throws Exception {
		/** ------------------验签开始---------------- **/
		String merchantId = params.get("merchantId");
		String version = params.get("version");
		String language = params.get("language");
		String signType = params.get("signType");
		String payType = params.get("payType");
		String issuerId = params.get("issuerId");
		String paymentOrderId = params.get("paymentOrderId");
		String tradeNo = params.get("orderNo");
		String orderDatetime = params.get("orderDatetime");
		String orderAmount = params.get("orderAmount");
		String payDatetime = params.get("payDatetime");
		String payAmount = params.get("payAmount");
		String ext1 = params.get("ext1");
		String ext2 = params.get("ext2");
		String payResult = params.get("payResult");
		String errorCode = params.get("errorCode");
		String returnDatetime = params.get("returnDatetime");
		String signMsg = params.get("signMsg");

		JSONObject result = new JSONObject();
		result.put("orderNo", tradeNo);

		List<PaymentLogDomain> logs = paymentLogService.getList("dealId", paymentOrderId);
		for(PaymentLogDomain log : logs){
			if(tradeNo.equals(log.getTradeNo())){
				if(log.getPaySuccess() == null || !log.getPaySuccess()){
					result.put("isSuccess", false);
					result.put("result", "error");
					return result.toString();
				}else {
					result.put("isSuccess", true);
					result.put("result", "result");
					return result.toString();
				}
			}
		}
	
		//验签是商户为了验证接收到的报文数据确实是支付网关发送的。
		//构造订单结果对象，验证签名。
		com.allinpay.ets.client.PaymentResult paymentResult = new com.allinpay.ets.client.PaymentResult();
		paymentResult.setMerchantId(merchantId);
		paymentResult.setVersion(version);
		paymentResult.setLanguage(language);
		paymentResult.setSignType(signType);
		paymentResult.setPayType(payType);
		paymentResult.setIssuerId(issuerId);
		paymentResult.setPaymentOrderId(paymentOrderId);
		paymentResult.setOrderNo(tradeNo);
		paymentResult.setOrderDatetime(orderDatetime);
		paymentResult.setOrderAmount(orderAmount);
		paymentResult.setPayDatetime(payDatetime);
		paymentResult.setPayAmount(payAmount);
		paymentResult.setExt1(ext1);
		paymentResult.setExt2(ext2);
		paymentResult.setPayResult(payResult);
		paymentResult.setErrorCode(errorCode);
		paymentResult.setReturnDatetime(returnDatetime);
		//signMsg为服务器端返回的签名值。
		paymentResult.setSignMsg(signMsg); 
		ComponentDomain component = componentService.get("componentId", getId());
		if(component.getIsOfficial() != null 
				&& component.getIsOfficial() == Boolean.TRUE){//正式环境证书
			//signType为"1"时，必须设置证书路径，请商户正确填写证书路径
			paymentResult.setCertPath(AppContext.getAppRealPath("/WEB-INF/certificate/TLCert.cer")); 
		}else{//测试环境证书
			//signType为"1"时，必须设置证书路径，请商户正确填写证书路径
			paymentResult.setCertPath(AppContext.getAppRealPath("/WEB-INF/certificate/TLCert-test.cer")); 
		}
		
		//验证签名：返回true代表验签成功；否则验签失败。
		boolean verifyResult = paymentResult.verify();
		
		//验签成功，还需要判断订单状态，为"1"表示支付成功。
		boolean paySuccess = verifyResult && payResult.equals("1");
		/**------------------验签结束----------------**/
		
		/**------------------判断是否已返回----------------**/
		BigDecimal amount = new BigDecimal(0);
		if(!StringUtils.isEmpty(payAmount)){
			amount = new BigDecimal(payAmount).divide(new BigDecimal(100), 2, BigDecimal.ROUND_DOWN);
		}

		if(memberId == null){
			result.put("isSuccess", false);
			result.put("result", "error");
			return result.toString();
		}
		MemberDomain member = memberService.find(memberId);
		if(member == null){
			result.put("isSuccess", false);
			result.put("result", "fail");
			return result.toString();
		}
		
		PaymentLogDomain paymentLog = new PaymentLogDomain();
		paymentLog.setOrderAccount(amount);
		paymentLog.setBankId(issuerId);
		paymentLog.setTradeNo(tradeNo);
		paymentLog.setMemberName(member.getUsername());
		paymentLog.setPayType(component.getPaymemtType());
		paymentLog.setDealId(paymentOrderId);
		paymentLog.setDealTime(DateHelper.string2Date(payDatetime, "yyyyMMddHHmmss"));
		paymentLog.setPayAmount(amount);
		paymentLogService.persist(paymentLog);//保存支付记录
		
		if(paySuccess){//支付成功
			boolean isSuccess = memberService.recharge(tradeNo, component.getPaymemtType(), amount, paymentOrderId, memberId);
			paymentLog.setPaySuccess(isSuccess);
			paymentLogService.update(paymentLog);//保存支付记录
			if(isSuccess && !isRecharge(tradeNo)){
				try {
					orderService.pay(tradeNo, component.getPaymemtType(), paymentOrderId);
					paymentLog.setPaySuccess(true);
					paymentLogService.update(paymentLog);//保存支付记录
				} catch (NoticeException e) {
					paymentLog.setPaySuccess(false);
					paymentLog.setErrorCode(e.getMessage());
					paymentLogService.update(paymentLog);//保存支付记录
				}
			}
			result.put("isSuccess", true);
			result.put("result", "result");
			return result.toString();
		}else{//支付失败
			paymentLog.setPaySuccess(false);
			paymentLog.setErrorCode(errorCode);
			paymentLogService.update(paymentLog);
			result.put("isSuccess", false);
			result.put("result", "fail");
			return result.toString();
		}
	}

	@Override
	public String getType() {
		return "payment";
	}

	@Override
	public String getId() {
		return "b2cAllinpayPlugin";
	}
	@Override
	public String getName() {
		return "通联支付";
	}

	@Override
	public String getVersion() {
		return "1.0.0";
	}

	@Override
	public String getAuthor() {
		return "fangchen";
	}

	@Override
	public void perform(Object... params) {
		
	}

	@Override
	public void register() {
		
	}

	@Override
	public String getTradeNo(Map<String, String> params) {
		return params.get("orderNo");
	}

}
